package com.woniuxy.yoga.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woniuxy.yoga.admin.dao.mapper.AdminAccountMapper;
import com.woniuxy.yoga.admin.dao.mapper.AdminRoleMapper;
import com.woniuxy.yoga.admin.dao.mapper.RoleMenuMapper;
import com.woniuxy.yoga.admin.dao.model.AdminAccount;
import com.woniuxy.yoga.admin.dao.model.AdminRole;
import com.woniuxy.yoga.admin.dao.model.Menu;
import com.woniuxy.yoga.admin.dao.mapper.MenuMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniuxy.yoga.admin.dao.model.RoleMenu;
import com.woniuxy.yoga.admin.model.dto.menu.MenuDTO;
import com.woniuxy.yoga.admin.model.dto.rolemenu.RoleMenuDTO;
import com.woniuxy.yoga.admin.model.exception.AdminException;
import com.woniuxy.yoga.admin.model.exception.AdminExceptionCode;
import com.woniuxy.yoga.admin.model.param.menu.*;
import com.woniuxy.yoga.admin.service.MenuService;
import com.woniuxy.yoga.commons.core.model.PageInfo;
import com.woniuxy.yoga.commons.core.statedata.AdminState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 韦用文,刘存益,郎腾霄
 * @since 2023年12月11日
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Autowired
    private MenuMapper menuMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    private RoleMenuMapper roleMenuMapper;
    @Autowired
    private AdminAccountMapper adminAccountMapper;
    /**
     * 新增一级菜单
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addFirstMenu(AddFirstMenuParam param) {
        //查询菜单名是否重复
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getMenuName,param.getMenuName());
        Menu menu = menuMapper.selectOne(wrapper);
        if (menu!=null) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_MENUNAME_REPEAT);
        }
        //查询一级菜单数量
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Menu::getParentId, AdminState.FIRST_MENU_PARENT_ID);
        List<Menu> menus = menuMapper.selectList(queryWrapper);
        Menu newMenu = BeanUtil.toBean(param, Menu.class);
        //若还没有父级菜单 则将path赋值为“1”
        if (menus==null||menus.size()==0) {
            newMenu.setMenuPath("1");
        }else {//若不为空，则将path赋值为最大的数字+1的字符串
            Optional<Integer> maxNumber = menus.stream()
                    .map(o -> o.getMenuPath())
                    .map(Integer::valueOf)
                    .max(Comparator.comparingInt(Integer::intValue));
            Integer max = maxNumber.get();
            newMenu.setMenuPath((max+1)+"");
        }
        //赋值父菜单Id
        newMenu.setParentId(AdminState.FIRST_MENU_PARENT_ID);
        //插入到菜单数据库中
        menuMapper.insertMenu(newMenu);
        //插入到角色菜单关联表中
        QueryWrapper<AdminRole> adminRoleQueryWrapper = new QueryWrapper<>();
        List<AdminRole> adminRoles = adminRoleMapper.selectList(adminRoleQueryWrapper);
        for (AdminRole adminRole : adminRoles) {
            RoleMenu roleMenu = new RoleMenu();
            roleMenu.setRoleId(adminRole.getRoleId());
            roleMenu.setMenuId(newMenu.getMenuId());
            //若为高级管理员则默认拥有全部菜单权限
            if (adminRole.getRoleId()== AdminState.HIGHTER_ADMIN) {
                roleMenu.setRelationState(AdminState.ROLE_RELATION_STATE_RIGHT);
            }else {//若为普通管理员则默认不拥有新菜单的权限
                roleMenu.setRelationState(AdminState.ROLE_RELATION_STATE_NO_RIGHT);
            }
            roleMenuMapper.insert(roleMenu);
        }
    }

    /**
     * 新增二级菜单
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addSeconMenu(AddSeconMenuParam param) {
        //查询菜单名是否重复
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getMenuName,param.getMenuName());
        Menu menu = menuMapper.selectOne(wrapper);
        if (menu!=null) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_MENUNAME_REPEAT);
        }
        //查询菜单路径是否重复
        LambdaQueryWrapper<Menu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Menu::getMenuPath,param.getMenuPath());
        Menu menuPath = menuMapper.selectOne(lambdaQueryWrapper);
        if (menuPath!=null) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_MENUNAME_REPEAT);
        }
        //查询父级菜单是否存在
        Menu parentMenu = menuMapper.selectById(param.getParentId());
        if (parentMenu==null) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_MENU_NOTEXISTS);
        }
        //转换
        Menu newMenu = BeanUtil.toBean(param, Menu.class);
        //插入进菜单数据库中
        menuMapper.insertMenu(newMenu);
        //插入到角色菜单关联表中
        QueryWrapper<AdminRole> adminRoleQueryWrapper = new QueryWrapper<>();
        List<AdminRole> adminRoles = adminRoleMapper.selectList(adminRoleQueryWrapper);
        for (AdminRole adminRole : adminRoles) {
            RoleMenu roleMenu = new RoleMenu();
            roleMenu.setRoleId(adminRole.getRoleId());
            roleMenu.setMenuId(newMenu.getMenuId());
            //若为高级管理员则默认拥有全部菜单权限
            if (adminRole.getRoleId()== AdminState.HIGHTER_ADMIN) {
                roleMenu.setRelationState(AdminState.ROLE_RELATION_STATE_RIGHT);
            }else {//若为普通管理员则默认不拥有新菜单的权限
                roleMenu.setRelationState(AdminState.ROLE_RELATION_STATE_NO_RIGHT);
            }
            roleMenuMapper.insert(roleMenu);
        }
    }

    /**
     * 管理员传入角色ID，分页查询该角色的所有一级权限
     * @param param
     * @return
     */
    @Override
    public PageInfo selectFirstByRoleId(SelectFirstByRoleIdParam param) {
        //查询当前角色信息
        AdminRole adminRole = adminRoleMapper.selectById(param.getRoleId());
        if (adminRole==null) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_ROLE_NOTEXISTS);
        }
        //查询当前角色的所有菜单权限
        LambdaQueryWrapper<RoleMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RoleMenu::getRoleId,param.getRoleId());
        if (param.getCurrent()==null) {
            param.setCurrent(1);
        }
        if (param.getSize()==null) {
            param.setSize(5);
        }
        //查询全部
        List<RoleMenu> roleMenus = roleMenuMapper.selectList(wrapper);
        ArrayList<RoleMenuDTO> roleMenuDTOS = new ArrayList<RoleMenuDTO>();
        //找出一级菜单权限
        for (RoleMenu roleMenu : roleMenus) {
            Menu menu = menuMapper.selectById(roleMenu.getMenuId());
            if (menu.getParentId()== AdminState.FIRST_MENU_PARENT_ID) {
                RoleMenuDTO roleMenuDTO = BeanUtil.toBean(roleMenu, RoleMenuDTO.class);
                roleMenuDTO.setMenuName(menu.getMenuName());
                roleMenuDTO.setMenuPath(menu.getMenuPath());
                roleMenuDTO.setRoleName(adminRole.getRoleName());
                roleMenuDTOS.add(roleMenuDTO);
            }
        }
        PageInfo pageInfo = new PageInfo();
        pageInfo.setSize(param.getSize());
        pageInfo.setCurrent(param.getCurrent());
        long total = roleMenuDTOS.size();
        Long pages = (total%param.getSize()==0)?(total/param.getSize()):(total/param.getSize())+1;
        pageInfo.setTotal(total);
        pageInfo.setPages(pages);
        int startIndex = (int) ((pageInfo.getCurrent()-1)*pageInfo.getSize());
        int endIndex = (int) Math.min(startIndex + pageInfo.getSize(), pageInfo.getTotal());
        List<RoleMenuDTO> list = roleMenuDTOS.subList(startIndex, endIndex);
        pageInfo.setRecords(list);
        return pageInfo;
    }

    /**
     * 管理员传入角色ID，分页查询该角色的所有二级权限
     * @param param
     * @return
     */
    @Override
    public PageInfo selectSeconByRoleId(SelectSeconByRoleIdParam param) {
        //查询当前角色信息
        AdminRole adminRole = adminRoleMapper.selectById(param.getRoleId());
        if (adminRole==null) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_ROLE_NOTEXISTS);
        }
        //查询当前角色的所有有权限的菜单权限
        LambdaQueryWrapper<RoleMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RoleMenu::getRoleId,param.getRoleId()).eq(RoleMenu::getRelationState,AdminState.ROLE_RELATION_STATE_RIGHT);
        List<RoleMenu> roleMenus = roleMenuMapper.selectList(wrapper);
        if (param.getSize()==null) {
            param.setSize(5);
        }
        if (param.getCurrent()==null) {
            param.setCurrent(1);
        }
        //将有权限的一级菜单下的二级菜单存入这个集合中
        ArrayList<RoleMenuDTO> roleMenuDTOS = new ArrayList<RoleMenuDTO>();
        //找出有权限的一级菜单
        for (RoleMenu roleMenu : roleMenus) {
            Menu menu = menuMapper.selectById(roleMenu.getMenuId());
            if (menu.getParentId()== AdminState.FIRST_MENU_PARENT_ID) {
                //通过一级菜单找到所属的二级菜单
                LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(Menu::getParentId,menu.getMenuId());
                List<Menu> menus = menuMapper.selectList(queryWrapper);
                for (Menu seconMenu : menus) {
                    LambdaQueryWrapper<RoleMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                    lambdaQueryWrapper.eq(RoleMenu::getMenuId,seconMenu.getMenuId())
                            .eq(RoleMenu::getRoleId,param.getRoleId());
                    RoleMenu seconRoleMenu = roleMenuMapper.selectOne(lambdaQueryWrapper);
                    RoleMenuDTO roleMenuDTO = BeanUtil.toBean(seconRoleMenu, RoleMenuDTO.class);
                    roleMenuDTO.setMenuName(seconMenu.getMenuName());
                    roleMenuDTO.setMenuPath(seconMenu.getMenuPath());
                    roleMenuDTO.setRoleName(adminRole.getRoleName());
                    roleMenuDTOS.add(roleMenuDTO);
                }
            }
        }
        //开始分页
        PageInfo pageInfo = new PageInfo();
        long total = roleMenuDTOS.size();
        Long pages = (total%param.getSize()==0)?(total/param.getSize()):(total/param.getSize())+1;
        //分页参数赋值
        pageInfo.setCurrent(param.getCurrent());
        pageInfo.setSize(param.getSize());
        pageInfo.setTotal(total);
        pageInfo.setPages(pages);
        int startIndex = (int) ((pageInfo.getCurrent()-1)*pageInfo.getSize());
        int endIndex = (int) Math.min(startIndex + pageInfo.getSize(), pageInfo.getTotal());
        List<RoleMenuDTO> list = roleMenuDTOS.subList(startIndex, endIndex);
        pageInfo.setRecords(list);
        return pageInfo;
    }

    /**
     * 取消菜单关联
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelRelation(CancelRelationParam param) {
        //查询该菜单是否存在
        Menu menu = menuMapper.selectById(param.getMenuId());
        if (menu==null) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_MENU_NOTEXISTS);
        }
        //查询该角色是否存在
        AdminRole adminRole = adminRoleMapper.selectById(param.getRoleId());
        if (adminRole==null) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_ROLE_NOTEXISTS);
        }
        //高级管理员不能被操作
        if (adminRole.getRoleId()== AdminState.HIGHTER_ADMIN) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_HIGHERADMIN_PROTECT);
        }
        //查询该菜单是否已关联
        LambdaQueryWrapper<RoleMenu> roleMenuLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roleMenuLambdaQueryWrapper.eq(RoleMenu::getRoleId,param.getRoleId()).eq(RoleMenu::getMenuId,param.getMenuId());
        RoleMenu roleMenu = roleMenuMapper.selectOne(roleMenuLambdaQueryWrapper);
        if (roleMenu.getRelationState()!= AdminState.ROLE_RELATION_STATE_RIGHT) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_RELATION_STATEERROR);
        }
        //若该菜单为一级菜单 则需要取消该菜单下的的二级菜单的关联
        if (menu.getParentId()== AdminState.FIRST_MENU_PARENT_ID) {
            LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Menu::getParentId,menu.getMenuId());
            List<Menu> menus = menuMapper.selectList(wrapper);
            for (Menu seconMenu : menus) {
                LambdaQueryWrapper<RoleMenu> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(RoleMenu::getMenuId,seconMenu.getMenuId())
                        .eq(RoleMenu::getRoleId,adminRole.getRoleId())
                        .eq(RoleMenu::getRelationState,AdminState.ROLE_RELATION_STATE_RIGHT);
                RoleMenu seconRoleMenu = roleMenuMapper.selectOne(queryWrapper);
                if (seconRoleMenu!=null) {
                    seconRoleMenu.setRelationState(AdminState.ROLE_RELATION_STATE_NO_RIGHT);
                    roleMenuMapper.updateById(seconRoleMenu);
                }
            }
        }
        //取消该菜单的关联
        roleMenu.setRelationState(AdminState.ROLE_RELATION_STATE_NO_RIGHT);
        roleMenuMapper.updateById(roleMenu);
    }

    /**
     * 关联菜单操作
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void renewRelation(RenewRelationParam param) {
        //查询该菜单是否存在
        Menu menu = menuMapper.selectById(param.getMenuId());
        if (menu==null) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_MENU_NOTEXISTS);
        }
        //查询该角色是否存在
        AdminRole adminRole = adminRoleMapper.selectById(param.getRoleId());
        if (adminRole==null) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_ROLE_NOTEXISTS);
        }
        //高级管理员不能被操作
        if (adminRole.getRoleId()== AdminState.HIGHTER_ADMIN) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_HIGHERADMIN_PROTECT);
        }
        //查询该菜单是否未关联
        LambdaQueryWrapper<RoleMenu> roleMenuLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roleMenuLambdaQueryWrapper.eq(RoleMenu::getRoleId,param.getRoleId()).eq(RoleMenu::getMenuId,param.getMenuId());
        RoleMenu roleMenu = roleMenuMapper.selectOne(roleMenuLambdaQueryWrapper);
        if (roleMenu.getRelationState()== AdminState.ROLE_RELATION_STATE_RIGHT) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_RELATION_STATEERROR);
        }
        //判断该菜单是否是二级菜单 若是则判断一级菜单是否关联 若一级菜单未关联则抛异常
        if (menu.getParentId()!= AdminState.FIRST_MENU_PARENT_ID) {
            LambdaQueryWrapper<RoleMenu> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(RoleMenu::getMenuId,menu.getParentId())
                    .eq(RoleMenu::getRoleId,param.getRoleId());
            RoleMenu firstRoleMenu = roleMenuMapper.selectOne(wrapper);
            if (firstRoleMenu.getRelationState()!= AdminState.ROLE_RELATION_STATE_RIGHT) {
                throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_RELATION_PARENTERROR);
            }
        }
        //关联该菜单
        roleMenu.setRelationState(AdminState.ROLE_RELATION_STATE_RIGHT);
        roleMenuMapper.updateById(roleMenu);
    }

    /**
     * 通过管理员账号，查询该账号所对应角色的菜单权限
     * @param accountId
     * @return
     */
    @Override
    public List<MenuDTO> selectMenuByAccountId(Integer accountId) {
        //查询该账号是否存在
        AdminAccount adminAccount = adminAccountMapper.selectById(accountId);
        if (adminAccount==null) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_ACCOUNT_NOTEXITS);
        }
        //查询该账号所对应的角色是否存在
        AdminRole adminRole = adminRoleMapper.selectById(adminAccount.getRoleId());
        if (adminRole==null) {
            throw new AdminException(AdminExceptionCode.ADMIN_EXCEPTION_CODE_ROLE_NOTEXISTS);
        }
        //查询该角色有权限的菜单关联
        LambdaQueryWrapper<RoleMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RoleMenu::getRoleId,adminRole.getRoleId()).eq(RoleMenu::getRelationState,AdminState.ROLE_RELATION_STATE_RIGHT);
        List<RoleMenu> roleMenus = roleMenuMapper.selectList(wrapper);
        //查询该角色有权限的菜单
        List<Menu> menus = new ArrayList<>();
        for (RoleMenu roleMenu : roleMenus) {
            Menu menu = menuMapper.selectById(roleMenu.getMenuId());
            menus.add(menu);
        }
        //找出其中的一级菜单
        ArrayList<MenuDTO> menuDTOS = new ArrayList<>();
        for (Menu menu : menus) {
            if (menu.getParentId()== AdminState.FIRST_MENU_PARENT_ID) {
                MenuDTO menuDTO = BeanUtil.toBean(menu, MenuDTO.class);
                menuDTOS.add(menuDTO);
            }
        }
        //找出其中一级菜单所对应的二级菜单
        for (MenuDTO menuDTO : menuDTOS) {
            ArrayList<MenuDTO> seconMenuDTOs = new ArrayList<>();
            for (Menu menu : menus) {
                if (menu.getParentId()==menuDTO.getMenuId()) {
                    MenuDTO seconMenuDTO = BeanUtil.toBean(menu, MenuDTO.class);
                    seconMenuDTOs.add(seconMenuDTO);
                }
            }
            menuDTO.setSeconMenus(seconMenuDTOs);
        }
        return menuDTOS;
    }

    /**
     * 查询所有一级菜单
     * @return
     */
    @Override
    public List<Menu> selectFirstMenu() {
        QueryWrapper<Menu> wrapper = new QueryWrapper<>();
        List<Menu> menus = menuMapper.selectList(wrapper);
        List<Menu> firstMenus = new ArrayList<>();
        for (Menu menu : menus) {
            if (menu.getParentId()== AdminState.FIRST_MENU_PARENT_ID) {
                firstMenus.add(menu);
            }
        }
        return firstMenus;
    }
}
